﻿namespace OpenComposite.EII.Simulation
{
	using System;
	using System.Collections.Generic;
	using System.Collections.ObjectModel;
	using System.ComponentModel;
	using System.ComponentModel.Design;
	using System.Drawing;
	using System.Globalization;
	using System.Reflection;
	using System.Text;
	using System.Windows.Forms;
	using System.Xml;

	using Aga.Controls.Tree;
	using Aga.Controls.Tree.NodeControls;

	using OpenComposite.EII.Designer.Workflow;
	using OpenComposite.Repository.Properties;
	using OpenComposite.EII.Repository;

	//public enum SelectedControl
	//{
	//	Invalid = 0,
	//	StartValue,
	//	EndValue
	//}
	public class EditableBusinessObjectTreeView : TreeViewAdv
	{
		#region Initialization

		/// <summary>
		/// Initializes a new instance of the <see cref="EditableBusinessObjectTreeView"/> class.
		/// </summary>
		public EditableBusinessObjectTreeView()
		{
			InitializeComponent();
			init();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="EditableBusinessObjectTreeView"/> class.
		/// </summary>
		/// <param name="bobject">The business object.</param>
		/// <param name="compiledAssembly">The compiled assembly.</param>
		/// <param name="wfController">The workflow controller.</param>
		public EditableBusinessObjectTreeView(BusinessObject bobject, Assembly compiledAssembly, WorkflowController wfController)
			: this()
		{
			_bobject = bobject;
			_compiledAssembly = compiledAssembly;
			_wfController = wfController;
			load();
		}

		#endregion Initialization

		#region Public Members

		#region Properties

		public NamedBusinessObjectCollection AdditionalBusinessObjects
		{
			get { return _additionalBObjects; }
			set { _additionalBObjects = value; }
		}

		/// <summary>
		/// Gets or sets the business object shown in the <see cref="TreeViewAdv"/>.
		/// </summary>
		/// <value>The business object.</value>
		public BusinessObject BusinessObject
		{
			get { return _bobject; }
			set { _bobject = value; }
		}

		/// <summary>
		/// Gets or sets the compiled assembly containing the <see cref="Type"></see> of the current business object.
		/// </summary>
		/// <value>The compiled assembly.</value>
		public Assembly CompiledAssembly
		{
			get { return _compiledAssembly; }
			set { _compiledAssembly = value; }
		}

		public BusinessObject InputBusinessObject
		{
			get { return _xmlBobject; }
			set { _xmlBobject = value; }
		}

		public XmlDocument InputDocument
		{
			get { return _xmlDoc; }
			set { _xmlDoc = value; }
		}

		public NamedBusinessObject NamedBusinessObject
		{
			get { return _nBobject; }
			set { _nBobject = value; }
		}

		public NamedBusinessObject OutputBusinesObject
		{
			get { return _outputBusinessObject; }
			set { _outputBusinessObject = value; }
		}

		/// <summary>
		/// Gets or sets a value indicating whether the TreeView is in read only mode.
		/// </summary>
		/// <value><c>true</c> if read only; otherwise, <c>false</c>.</value>
		public bool ReadOnly
		{
			get { return _readOnly; }
		}

		/// <summary>
		/// Gets the root node. (Representing the shown business object)
		/// </summary>
		/// <value>The root node.</value>
		public Node RootNode
		{
			get { return rootNode; }
		}

		public NamedBusinessObjectCollection SubscribedBusinessObjects
		{
			get { return _bobjects; }
			set { _bobjects = value; }
		}

		/// <summary>
		/// Gets or sets the workflow controller.
		/// </summary>
		/// <value>The workflow controller.</value>
		public WorkflowController WorkflowController
		{
			get { return _wfController; }
			set { _wfController = value; }
		}

		#endregion Properties

		#region Methods

		public SimulationVariable AddListElementToNode(SimulationVariable selected)
		{
			SimulationVariable listVar = new SimulationVariable(string.Format("{0} {1}", selected.Field.DataType, selected.Nodes.Count + 1), selected.Field);
			listVar.Image = ImageBusinessObject;
			foreach ( BusinessObjectField subField in selected.Field.BusinessObject.BusinessObjectFields ) {
				listVar.Nodes.Add(createNodeRow(subField));
			}
			selected.Nodes.Add(listVar);
			TreeNodeAdv current = this.FindNodeByTag(listVar);
			if ( current != null ) current.ExpandAll();
			return listVar;
		}

		public void ClearBusinessObjectValues()
		{
			foreach ( TreeNodeAdv node in this.AllNodes ) {
				SimulationVariable simVar = node.Tag as SimulationVariable;
				if ( simVar == null ) continue;
				simVar.StartValue = null;
			}
		}

		/// <summary>
		/// Creates the <see cref="Object"></see> of the business object.
		/// </summary>
		/// <param name="variable">The <see cref="SimulationVariable"/> to create.</param>
		/// <returns>The input object</returns>
		public object CreateInputObject(SimulationVariable variable)
		{
			if ( _readOnly ) throw new InvalidOperationException("Cannot create input object while in read only mode");
			object obj = null;
			string dataNamespace = _wfController.FullClassName.Remove(_wfController.FullClassName.LastIndexOf(_wfController.RepositoryItem.Name)) + "Data.";
			Type inputType = _compiledAssembly.GetType(dataNamespace + variable.DataType);
			ConstructorInfo ctor = inputType.GetConstructor(Type.EmptyTypes);
			obj = ctor.Invoke(null);

			foreach ( Node node in variable.Nodes ) {
				SimulationVariable simVar = node as SimulationVariable;
				if ( simVar == null ) throw new NullReferenceException("simVar is null. at createInputObject()");
				PropertyInfo prop = inputType.GetProperty(simVar.VarName);
				bool isList = prop == null && simVar.Field.IsList;
				if ( isList ) {
					prop = inputType.GetProperty("Item");
					for ( int i = 0; i < simVar.Nodes.Count; i++ ) {
						SimulationVariable childVar = simVar.Nodes[i] as SimulationVariable;
						if ( childVar == null ) throw new NullReferenceException("childVar is  null. at createInputObject()");
						MethodInfo meth = inputType.GetMethod("Add");
						Type varType = inputType.BaseType.GetGenericArguments()[0];
						meth.Invoke(obj, new object[] { createNestedObject(childVar, varType) });
						//prop.SetValue(obj, createNestedObject(simVar, prop), new object[] { i });
					}
					//prop
					//System.Collections.ICollection list = obj as System.Collections.ICollection;
					//if ( list != null ) {
					//    for ( int i = 0; i < list.Count; i++ ) {
					//        obj.GetType()
					//    }
					//}
				} else if ( simVar.Field.BusinessObjectID > 0 ) {
					prop.SetValue(obj, createNestedObject(simVar, prop.PropertyType), null);
				} else if ( simVar.Field.NounID > 0 ) {
					SetPropertyValue(prop, inputType, obj, calculateSimCycleRowItem(simVar));
					//prop.SetValue(obj, calculateSimCycleRowItem(simVar), null);
					//if ( needsSpecifiedFlag(prop.PropertyType) ) {
					//    PropertyInfo propSpecified = inputType.GetProperty(string.Format("{0}Specified", simVar.VarName));
					//    propSpecified.SetValue(obj, true, null);
					//}
				}
			}
			return obj;
		}

		/// <summary>
		/// Loads this instance. Aborts on error.
		/// </summary>
		public void Load()
		{
			load();
		}

		/// <summary>
		/// Reads a object and displays the values in the TreeViewAdv
		/// </summary>
		/// <param name="obj">A object containing the object that represents the RootNode of this instance (e.g. Orchestration)</param>
		public void ReadObject(object obj)
		{
			SimulationVariable inputObject = rootNode as SimulationVariable;
			//string dataNamespace = _wfController.FullClassName.Remove(_wfController.FullClassName.LastIndexOf(_wfController.RepositoryItem.Name)) + "Data.";
			Type orchestrationType = obj.GetType();
			PropertyInfo rootProperty = orchestrationType.GetProperty(inputObject.VarName);
			object rootValue = rootProperty.GetValue(obj, null);
			ReadObject(rootValue, rootProperty);
		}

		public void ReadObject(object obj, bool readAll)
		{
			if ( readAll ) {
				if ( this.Model == null ) return;
				foreach ( Node node in ( (TreeModel)this.Model ).Root.Nodes ) {
					rootNode = node;
					SimulationVariable inputObject = node as SimulationVariable;
					if ( node.Tag == null && ( node as SimulationVariable ).Field == null ) {
						foreach ( Node folderItem in node.Nodes ) {
							rootNode = folderItem;
							if ( inputObject.VarName == "Input Document" ) {
								inputObject = folderItem as SimulationVariable;
								if ( _xmlDoc != null ) {
									XmlNode xmlNode = _xmlDoc.DocumentElement;
									ReadObjectFromXml(xmlNode);
								} else { }
							} else {
								inputObject = folderItem as SimulationVariable;
								Type orchestrationType = obj.GetType();
								PropertyInfo rootProperty = orchestrationType.GetProperty(inputObject.VarName);
								if ( rootProperty == null ) continue;
								object rootValue = rootProperty.GetValue(obj, null);
								ReadObject(rootValue, rootProperty);
							}
						}
					} else {
						Type orchestrationType = obj.GetType();
						PropertyInfo rootProperty = orchestrationType.GetProperty(inputObject.VarName);
						if ( rootProperty != null ) {
							object rootValue = rootProperty.GetValue(obj, null);
							ReadObject(rootValue, rootProperty);
						}
					}
				}
			} else {
				ReadObject(obj);
			}
		}

		/// <summary>
		/// Reads a object and displays the values in the TreeViewAdv
		/// </summary>
		/// <param name="rootValue">A object representing the RootNode of this instance</param>
		/// <param name="rootProperty">PropertyInfo for the object to read</param>
		public void ReadObject(object rootValue, PropertyInfo rootProperty)
		{
			SimulationVariable inputObject = rootNode as SimulationVariable;
			if ( rootValue == null ) return;

			foreach ( Node node in inputObject.Nodes ) {
				SimulationVariable simVar = node as SimulationVariable;
				if ( simVar == null ) throw new NullReferenceException("simVar is null. at ReadObject()");
				PropertyInfo prop = rootProperty.PropertyType.GetProperty(simVar.VarName);
				if ( simVar.Field.BusinessObjectID > 0 ) {
					object obj = null;
					if ( ( simVar.Field.IsList ) &&
						 ( rootProperty.PropertyType.IsArray || rootProperty.PropertyType.GetMethod("Add") != null ) ) {
						int count = 0;
						bool isArray = rootProperty.PropertyType.IsArray;
						if ( isArray ) {
							count = (int)rootProperty.PropertyType.GetProperty("Length").GetValue(rootValue, null);
							//varType = property.PropertyType.GetElementType();
						} else {
							count = (int)rootProperty.PropertyType.GetProperty("Count").GetValue(rootValue, null);
							//varType = property.PropertyType.BaseType.GetGenericArguments()[0];
						}
						for ( int i = 0; i < count; i++ ) {
							if ( simVar.Nodes.Count < count ) AddListElementToNode(simVar);
							SimulationVariable childVar = simVar.Nodes[i] as SimulationVariable;
							if ( childVar == null ) throw new NullReferenceException("childVar is null. at ReadObject()");
							prop = rootProperty.PropertyType.GetProperty("Item");
							obj = prop.GetValue(rootValue, new object[] { i });
							readNestedObject(childVar, rootValue, obj, prop);
						}
					} else {
						obj = prop.GetValue(rootValue, null);
						if ( obj == null ) {
							simVar.StartValue = null;
							//simVar.EndValue = null;
							break;
						} else {
							readNestedObject(simVar, rootValue, obj, prop);
						}
					}
				} else if ( simVar.Field.NounID > 0 ) {
					object val = prop.GetValue(rootValue, null);
					simVar.StartValue = val == null ? null : val.ToString();
				}
			}
			this.FullUpdate();
		}

		#endregion Methods

		#endregion Public Members

		#region Internal Members

		#region Static Properties

		internal static Bitmap ImageBusinessObject
		{
			get
			{
				if ( _imgBObject == null ) {
					Bitmap bmp = Resources.bobject;
					bmp.MakeTransparent(Color.Magenta);
					_imgBObject = bmp;
				}
				return _imgBObject;
			}
		}

		internal static Bitmap ImageBusinessObjectList
		{
			get
			{
				if ( _imgList == null ) {
					Bitmap bmp = Resources.list_of_bobjects;
					bmp.MakeTransparent(Color.Magenta);
					_imgList = bmp;
				}
				return _imgList;
			}
		}

		internal static Bitmap ImageFolder
		{
			get
			{
				if ( _imgFolder == null ) {
					Bitmap bmp = Resources.folder_closed;
					bmp.MakeTransparent(Color.Magenta);
					_imgFolder = bmp;
				}
				return _imgFolder;
			}
		}

		internal static Bitmap ImageNoun
		{
			get
			{
				if ( _imgNoun == null ) {
					Bitmap bmp = Resources.png_field;
					bmp.MakeTransparent(Color.Magenta);
					_imgNoun = bmp;
				}
				return _imgNoun;
			}
		}

		#endregion Static Properties

		#endregion Internal Members

		#region Private Members

		#region Static Fields

		private static Bitmap _imgBObject = null;
		private static Bitmap _imgFolder = null;
		private static Bitmap _imgList = null;
		private static Bitmap _imgNoun = null;

		#endregion Static Fields

		#region Fields

		private NamedBusinessObjectCollection _additionalBObjects = null;
		private BusinessObject _bobject = null;
		private NamedBusinessObjectCollection _bobjects = null;
		private Assembly _compiledAssembly;
		private NamedBusinessObject _nBobject = null;
		private NamedBusinessObject _outputBusinessObject = null;
		private Random _random = new Random();
		private bool _readOnly = false;
		private NodeControlInfo _selectedNode = NodeControlInfo.Empty;
		private WorkflowController _wfController = null;
		private BusinessObject _xmlBobject = null;
		private XmlDocument _xmlDoc = null;
		private System.Windows.Forms.ToolStripMenuItem addItemToolStripMenuItem;
		private MonthCalendar calendar;
		private System.Windows.Forms.ToolStripMenuItem clearFieldToolStripMenuItem;
		private ToolStripMenuItem collapseAllToolStripMenuItem;
		private System.ComponentModel.IContainer components;
		private System.Windows.Forms.ContextMenuStrip ctxMenuVars;
		private ToolStripMenuItem editDateToolStropMenuItem;
		private ToolStripMenuItem expandAllToolStripMenuItem;
		private SimulationVariable inputFolder = null;
		private System.Windows.Forms.ToolStripMenuItem insertToolStripMenuItem;
		private System.Windows.Forms.ToolStripMenuItem insert_cityToolStripMenuItem;
		private System.Windows.Forms.ToolStripMenuItem insert_dateToolStripMenuItem;
		private System.Windows.Forms.ToolStripMenuItem insert_firstNameToolStripMenuItem;
		private System.Windows.Forms.ToolStripMenuItem insert_fullNameToolStripMenuItem;
		private System.Windows.Forms.ToolStripMenuItem insert_lastNameToolStripMenuItem;
		private Aga.Controls.Tree.NodeControls.NodeTextBox nodeCtrlDataType;
		private Aga.Controls.Tree.NodeControls.NodeIcon nodeCtrlIcon;
		private Aga.Controls.Tree.NodeControls.NodeTextBox nodeCtrlStartVal;
		private Aga.Controls.Tree.NodeControls.NodeTextBox nodeCtrlVarName;
		private SimulationVariable othersFolder = null;
		private SimulationVariable outputFolder = null;
		private System.Windows.Forms.ToolStripMenuItem removeItemToolStripMenuItem;
		private Node rootNode = null;
		private SimulationVariable subscribedFolder = null;
		private ToolStripSeparator toolStripSeparator1;
		private System.Windows.Forms.ToolStripSeparator toolStripSeparator3;
		private Aga.Controls.Tree.TreeColumn tvColDataType;
		private Aga.Controls.Tree.TreeColumn tvColStartVal;
		private Aga.Controls.Tree.TreeColumn tvColVarName;

		#endregion Fields

		#region Static Properties

		private static List<string> Cities
		{
			get
			{
				List<string> list = new List<string>();
				list.Add("Los Angeles");
				list.Add("New York");
				list.Add("San Francisco");
				list.Add("Boston");
				list.Add("Denver");
				list.Add("Paris");
				list.Add("Berlin");
				list.Add("Munich");
				list.Add("London");
				return list;
			}
		}

		private static List<string> FirstNames
		{
			get
			{
				List<string> list = new List<string>();
				list.Add("Alex");
				list.Add("Anna");
				list.Add("Barbara");
				list.Add("Ben");
				list.Add("Bob");
				list.Add("Cesar");
				list.Add("Franz");
				list.Add("Gustav");
				list.Add("Hans");
				list.Add("John");
				list.Add("Sandra");
				return list;
			}
		}

		private static List<string> LastNames
		{
			get
			{
				List<string> list = new List<string>();
				list.Add("Andersion");
				list.Add("Barker");
				list.Add("Huggins");
				list.Add("Summers");
				list.Add("Doe");
				return list;
			}
		}

		#endregion Static Properties

		#region Event Handlers

		protected override void OnKeyUp(KeyEventArgs e)
		{
			base.OnKeyUp(e);
		}
		protected override void OnKeyPress(KeyPressEventArgs e)
		{
			if ( _readOnly || e.Handled ) return;
			NodeTextBox ntxt = nodeCtrlStartVal;
			if ( ntxt == null || !ntxt.EditEnabled ) return;
			if ( char.IsLetterOrDigit(e.KeyChar) || char.IsSymbol(e.KeyChar) ) {
				ntxt.BeginEdit(this.SelectedNode, e.KeyChar.ToString());
			}
			e.Handled = true;
			base.OnKeyPress(e);
		}

		private void EditableBusinessObjectTreeView_MouseDown(object sender, MouseEventArgs e)
		{
			calendar.Hide();
			#region old
			//if ( _readOnly ) {
			//    this.ContextMenuStrip = null;
			//    Form.Equals(null, null);
			//    Point p = Form.MousePosition;
			//    return;
			//} else {
			//    this.ContextMenuStrip = ctxMenuVars;
			//}
			//if ( e.Button == MouseButtons.Right ) {
			//    _selectedNode = this.GetNodeControlInfoAt(e.Location);
			//    SimulationVariable var = null;
			//    if ( this.SelectedNode != null ) var = this.SelectedNode.Tag as SimulationVariable;
			//    if ( this.SelectedNode == null || var == null || var.Field == null ) {
			//        clearFieldToolStripMenuItem.Enabled = false;
			//        toolStripSeparator3.Visible = false;
			//        insertToolStripMenuItem.Enabled = false;
			//        insertToolStripMenuItem.Visible = false;
			//        addItemToolStripMenuItem.Enabled = false;
			//        addItemToolStripMenuItem.Visible = false;
			//        removeItemToolStripMenuItem.Enabled = false;
			//        removeItemToolStripMenuItem.Visible = false;
			//        return;
			//    }
			//    bool activated = var.Field != null && // field == null for RootElement
			//        !( var.Field.BusinessObjectID > 0 ||
			//        _selectedNode.Control != nodeCtrlStartVal );

			//    clearFieldToolStripMenuItem.Enabled = activated;
			//    toolStripSeparator3.Visible = activated;
			//    insertToolStripMenuItem.Enabled = activated;
			//    insertToolStripMenuItem.Visible = activated;
			//    if ( var.Field.MaxOccurs == -1 || ( var.Field.MinOccurs > 1 && var.Field.MinOccurs >= var.Nodes.Count ) ) {
			//        if ( var.DataType.StartsWith("List of") ) {
			//            addItemToolStripMenuItem.Enabled = true;
			//            addItemToolStripMenuItem.Visible = true;
			//            removeItemToolStripMenuItem.Enabled = false;
			//            removeItemToolStripMenuItem.Visible = false;
			//        } else {
			//            addItemToolStripMenuItem.Enabled = false;
			//            addItemToolStripMenuItem.Visible = false;
			//            removeItemToolStripMenuItem.Enabled = true;
			//            removeItemToolStripMenuItem.Visible = true;
			//        }
			//    } else {
			//        addItemToolStripMenuItem.Enabled = false;
			//        addItemToolStripMenuItem.Visible = false;
			//        removeItemToolStripMenuItem.Enabled = false;
			//        removeItemToolStripMenuItem.Visible = false;
			//    }
			//}
			#endregion
		}

		private void EditableBusinessObjectTreeView_SelectionChanged(object sender, EventArgs e)
		{
			clearFieldToolStripMenuItem.Enabled = false;
			toolStripSeparator3.Visible = false;
			insertToolStripMenuItem.Enabled = false;
			insertToolStripMenuItem.Visible = false;
			addItemToolStripMenuItem.Enabled = false;
			addItemToolStripMenuItem.Visible = false;
			removeItemToolStripMenuItem.Enabled = false;
			removeItemToolStripMenuItem.Visible = false;
			//if ( Form.MouseButtons == MouseButtons.Right ) {
			if ( _readOnly ) return;
			_selectedNode = this.GetNodeControlInfoAt(this.PointToClient(Form.MousePosition));
			SimulationVariable var = null;
			if ( this.SelectedNode != null ) var = this.SelectedNode.Tag as SimulationVariable;
			if ( this.SelectedNode == null || var == null || var.Field == null ) {
				return;
			}
			bool activated = var.Field != null && // field == null for RootElement
				!( var.Field.BusinessObjectID > 0 /*||
					_selectedNode.Control != nodeCtrlStartVal*/
															   );
			editDateToolStropMenuItem.Visible = ( var.DataType == "dateTime" );
			editDateToolStropMenuItem.Enabled = ( var.DataType == "dateTime" );

			clearFieldToolStripMenuItem.Enabled = activated;
			toolStripSeparator3.Visible = activated;
			insertToolStripMenuItem.Enabled = activated;
			insertToolStripMenuItem.Visible = activated;
			if ( var.Field.MaxOccurs == -1 || ( var.Field.MinOccurs > 1 && var.Field.MinOccurs >= var.Nodes.Count ) ) {
				if ( var.DataType.StartsWith("List of") ) {
					addItemToolStripMenuItem.Enabled = true;
					addItemToolStripMenuItem.Visible = true;
					removeItemToolStripMenuItem.Enabled = false;
					removeItemToolStripMenuItem.Visible = false;
				} else {
					addItemToolStripMenuItem.Enabled = false;
					addItemToolStripMenuItem.Visible = false;
					removeItemToolStripMenuItem.Enabled = true;
					removeItemToolStripMenuItem.Visible = true;
				}
			} else {
				addItemToolStripMenuItem.Enabled = false;
				addItemToolStripMenuItem.Visible = false;
				removeItemToolStripMenuItem.Enabled = false;
				removeItemToolStripMenuItem.Visible = false;
			}
			//}
		}

		private void addItemToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( this.SelectedNode == null ) return;
			SimulationVariable selected = this.SelectedNode.Tag as SimulationVariable;
			if ( ( selected.Field.MaxOccurs == -1 ||
				 ( selected.Field.MinOccurs > 1 && selected.Field.MinOccurs >= selected.Nodes.Count ) ) &&
				  !selected.DataType.StartsWith("List of") ) return;

			AddListElementToNode(selected);
		}

		private void calender_DateSelected(object sender, DateRangeEventArgs e)
		{
			if ( SelectedNode == null ) return;
			SimulationVariable simVar = SelectedNode.Tag as SimulationVariable;
			simVar.StartValue = e.Start.ToString();
			calendar.Hide();
		}

		private void calender_Leave(object sender, EventArgs e)
		{
			if ( calendar.Visible ) calendar.Hide();
		}

		void calender_LostFocus(object sender, EventArgs e)
		{
			calendar.Hide();
		}

		private void calender_MouseCaptureChanged(object sender, EventArgs e)
		{
			MonthCalendar.HitTestInfo info = calendar.HitTest(calendar.PointToClient(MousePosition));
			if ( info.HitArea == MonthCalendar.HitArea.Nowhere ) {
				calendar.Hide();
			}
		}

		private void clearFieldToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( this.SelectedNode == null ) return;
			SimulationVariable selected = this.SelectedNode.Tag as SimulationVariable;
			setSelectedNodeValue(selected, null);
		}

		void collapseAllToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.CollapseAll();
		}

		private void ctxMenuVars_Opening(object sender, CancelEventArgs e)
		{
		}

		private void editDateToolStropMenuItem_Click(object sender, EventArgs e)
		{
			if ( SelectedNode == null ) return;
			SimulationVariable simVar = SelectedNode.Tag as SimulationVariable;
			if ( simVar.DataType == "dateTime" ) {
				//ToolStripMenuItem editDateItem = sender as ToolStripMenuItem;
				//if ( editDateItem == null ) return;
				//calendar.Location = PointToClient(editDateItem.Owner.Location);
				//int diff = this.Bottom - calendar.Bottom;

				//calendar.Location = new Point(calendar.Location.X, calendar.Location.Y + diff);
				Point defaultPoint = this.PointToClient(ctxMenuVars.Bounds.Location);//new Point(SelectedControl.Bounds.X, SelectedControl.Bounds.Bottom);
				if ( defaultPoint.Y + calendar.Height > this.Height ) {
					defaultPoint = new Point(defaultPoint.X, defaultPoint.Y - calendar.Height);
				}
				//calendar.Location = new Point(SelectedControl.Bounds.X, SelectedControl.Bounds.Bottom);
				calendar.Location = defaultPoint;
				calendar.Show();
			}
		}

		void expandAllToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.ExpandAll();
		}

		private void insert_cityToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( this.SelectedNode == null ) return;
			SimulationVariable selected = this.SelectedNode.Tag as SimulationVariable;
			setSelectedNodeValue(selected, RandomCity());
		}

		private void insert_dateToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( this.SelectedNode == null ) return;
			SimulationVariable selected = this.SelectedNode.Tag as SimulationVariable;
			setSelectedNodeValue(selected, RandomDate().ToString());
		}

		private void insert_firstNameToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( this.SelectedNode == null ) return;
			SimulationVariable selected = this.SelectedNode.Tag as SimulationVariable;
			setSelectedNodeValue(selected, RandomFirstName());
		}

		private void insert_fullNameToolStripMenuItem_Click(object sender, EventArgs e)
		{
			SimulationVariable selected = this.SelectedNode.Tag as SimulationVariable;
			setSelectedNodeValue(selected, RandomFullName());
		}

		private void insert_lastNameToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( this.SelectedNode == null ) return;
			SimulationVariable selected = this.SelectedNode.Tag as SimulationVariable;
			setSelectedNodeValue(selected, RandomLastName());
		}

		private void nodeCtrlStartVal_IsEditEnabledValueNeeded(object sender, NodeControlValueEventArgs e)
		{
			e.Value = !_readOnly && ( ( e.Node.Tag as Node ).Tag is Noun );
		}

		private void removeItemToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( this.SelectedNode == null ) return;
			SimulationVariable selected = this.SelectedNode.Tag as SimulationVariable;

			selected.Parent.Nodes.Remove(selected);
		}

		#endregion Event Handlers

		#region Methods

		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.ctxMenuVars = new System.Windows.Forms.ContextMenuStrip(this.components);
			this.expandAllToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.collapseAllToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
			this.clearFieldToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
			this.insertToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.insert_firstNameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.insert_lastNameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.insert_fullNameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.insert_cityToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.insert_dateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.addItemToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.removeItemToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.editDateToolStropMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.tvColVarName = new Aga.Controls.Tree.TreeColumn();
			this.tvColDataType = new Aga.Controls.Tree.TreeColumn();
			this.tvColStartVal = new Aga.Controls.Tree.TreeColumn();
			this.nodeCtrlIcon = new Aga.Controls.Tree.NodeControls.NodeIcon();
			this.nodeCtrlVarName = new Aga.Controls.Tree.NodeControls.NodeTextBox();
			this.nodeCtrlDataType = new Aga.Controls.Tree.NodeControls.NodeTextBox();
			this.nodeCtrlStartVal = new Aga.Controls.Tree.NodeControls.NodeTextBox();
			this.calendar = new System.Windows.Forms.MonthCalendar();
			this.ctxMenuVars.SuspendLayout();
			this.SuspendLayout();
			//
			// ctxMenuVars
			//
			this.ctxMenuVars.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
			this.expandAllToolStripMenuItem,
			this.collapseAllToolStripMenuItem,
			this.toolStripSeparator1,
			this.clearFieldToolStripMenuItem,
			this.toolStripSeparator3,
			this.insertToolStripMenuItem,
			this.addItemToolStripMenuItem,
			this.removeItemToolStripMenuItem,
			this.editDateToolStropMenuItem});
			this.ctxMenuVars.Name = "ctxMenuVars";
			this.ctxMenuVars.Size = new System.Drawing.Size(169, 170);
			this.ctxMenuVars.Opening += new System.ComponentModel.CancelEventHandler(this.ctxMenuVars_Opening);
			//
			// expandAllToolStripMenuItem
			//
			this.expandAllToolStripMenuItem.Image = global::OpenComposite.Repository.Properties.Resources.tree_expandall;
			this.expandAllToolStripMenuItem.Name = "expandAllToolStripMenuItem";
			this.expandAllToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
			this.expandAllToolStripMenuItem.Text = "Expand All";
			this.expandAllToolStripMenuItem.Click += new System.EventHandler(this.expandAllToolStripMenuItem_Click);
			//
			// collapseAllToolStripMenuItem
			//
			this.collapseAllToolStripMenuItem.Image = global::OpenComposite.Repository.Properties.Resources.tree_collapseall;
			this.collapseAllToolStripMenuItem.Name = "collapseAllToolStripMenuItem";
			this.collapseAllToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
			this.collapseAllToolStripMenuItem.Text = "Collapse All";
			this.collapseAllToolStripMenuItem.Click += new System.EventHandler(this.collapseAllToolStripMenuItem_Click);
			//
			// toolStripSeparator1
			//
			this.toolStripSeparator1.Name = "toolStripSeparator1";
			this.toolStripSeparator1.Size = new System.Drawing.Size(165, 6);
			//
			// clearFieldToolStripMenuItem
			//
			this.clearFieldToolStripMenuItem.Name = "clearFieldToolStripMenuItem";
			this.clearFieldToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
			this.clearFieldToolStripMenuItem.Text = "&Clear Field";
			this.clearFieldToolStripMenuItem.Click += new System.EventHandler(this.clearFieldToolStripMenuItem_Click);
			//
			// toolStripSeparator3
			//
			this.toolStripSeparator3.Name = "toolStripSeparator3";
			this.toolStripSeparator3.Size = new System.Drawing.Size(165, 6);
			//
			// insertToolStripMenuItem
			//
			this.insertToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
			this.insert_firstNameToolStripMenuItem,
			this.insert_lastNameToolStripMenuItem,
			this.insert_fullNameToolStripMenuItem,
			this.insert_cityToolStripMenuItem,
			this.insert_dateToolStripMenuItem});
			this.insertToolStripMenuItem.Name = "insertToolStripMenuItem";
			this.insertToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
			this.insertToolStripMenuItem.Text = "&Insert Random...";
			//
			// insert_firstNameToolStripMenuItem
			//
			this.insert_firstNameToolStripMenuItem.Name = "insert_firstNameToolStripMenuItem";
			this.insert_firstNameToolStripMenuItem.Size = new System.Drawing.Size(129, 22);
			this.insert_firstNameToolStripMenuItem.Text = "&First name";
			this.insert_firstNameToolStripMenuItem.Click += new System.EventHandler(this.insert_firstNameToolStripMenuItem_Click);
			//
			// insert_lastNameToolStripMenuItem
			//
			this.insert_lastNameToolStripMenuItem.Name = "insert_lastNameToolStripMenuItem";
			this.insert_lastNameToolStripMenuItem.Size = new System.Drawing.Size(129, 22);
			this.insert_lastNameToolStripMenuItem.Text = "&Last name";
			this.insert_lastNameToolStripMenuItem.Click += new System.EventHandler(this.insert_lastNameToolStripMenuItem_Click);
			//
			// insert_fullNameToolStripMenuItem
			//
			this.insert_fullNameToolStripMenuItem.Name = "insert_fullNameToolStripMenuItem";
			this.insert_fullNameToolStripMenuItem.Size = new System.Drawing.Size(129, 22);
			this.insert_fullNameToolStripMenuItem.Text = "Full &name";
			this.insert_fullNameToolStripMenuItem.Click += new System.EventHandler(this.insert_fullNameToolStripMenuItem_Click);
			//
			// insert_cityToolStripMenuItem
			//
			this.insert_cityToolStripMenuItem.Name = "insert_cityToolStripMenuItem";
			this.insert_cityToolStripMenuItem.Size = new System.Drawing.Size(129, 22);
			this.insert_cityToolStripMenuItem.Text = "&City";
			this.insert_cityToolStripMenuItem.Click += new System.EventHandler(this.insert_cityToolStripMenuItem_Click);
			//
			// insert_dateToolStripMenuItem
			//
			this.insert_dateToolStripMenuItem.Name = "insert_dateToolStripMenuItem";
			this.insert_dateToolStripMenuItem.Size = new System.Drawing.Size(129, 22);
			this.insert_dateToolStripMenuItem.Text = "&Date";
			this.insert_dateToolStripMenuItem.Click += new System.EventHandler(this.insert_dateToolStripMenuItem_Click);
			//
			// addItemToolStripMenuItem
			//
			this.addItemToolStripMenuItem.Name = "addItemToolStripMenuItem";
			this.addItemToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Insert;
			this.addItemToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
			this.addItemToolStripMenuItem.Text = "&Add Item";
			this.addItemToolStripMenuItem.Visible = false;
			this.addItemToolStripMenuItem.Click += new System.EventHandler(this.addItemToolStripMenuItem_Click);
			//
			// removeItemToolStripMenuItem
			//
			this.removeItemToolStripMenuItem.Name = "removeItemToolStripMenuItem";
			this.removeItemToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Delete;
			this.removeItemToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
			this.removeItemToolStripMenuItem.Text = "&Remove Item";
			this.removeItemToolStripMenuItem.Visible = false;
			this.removeItemToolStripMenuItem.Click += new System.EventHandler(this.removeItemToolStripMenuItem_Click);
			//
			// editDateToolStropMenuItem
			//
			this.editDateToolStropMenuItem.Enabled = false;
			this.editDateToolStropMenuItem.Name = "editDateToolStropMenuItem";
			this.editDateToolStropMenuItem.Size = new System.Drawing.Size(168, 22);
			this.editDateToolStropMenuItem.Text = "Edit Date";
			this.editDateToolStropMenuItem.Visible = false;
			this.editDateToolStropMenuItem.Click += new System.EventHandler(this.editDateToolStropMenuItem_Click);
			//
			// tvColVarName
			//
			this.tvColVarName.Header = "Variable Name";
			this.tvColVarName.MinColumnWidth = 180;
			this.tvColVarName.SortOrder = System.Windows.Forms.SortOrder.None;
			this.tvColVarName.TooltipText = null;
			this.tvColVarName.Width = 180;
			//
			// tvColDataType
			//
			this.tvColDataType.Header = "Data Type";
			this.tvColDataType.MinColumnWidth = 170;
			this.tvColDataType.SortOrder = System.Windows.Forms.SortOrder.None;
			this.tvColDataType.TooltipText = null;
			this.tvColDataType.Width = 170;
			//
			// tvColStartVal
			//
			this.tvColStartVal.Header = "Value";
			this.tvColStartVal.MinColumnWidth = 150;
			this.tvColStartVal.SortOrder = System.Windows.Forms.SortOrder.None;
			this.tvColStartVal.TooltipText = null;
			this.tvColStartVal.Width = 150;
			//
			// nodeCtrlIcon
			//
			this.nodeCtrlIcon.Bounds = new System.Drawing.Rectangle(0, 0, 0, 0);
			this.nodeCtrlIcon.DataPropertyName = "Image";
			this.nodeCtrlIcon.LeftMargin = 1;
			this.nodeCtrlIcon.ParentColumn = this.tvColVarName;
			//
			// nodeCtrlVarName
			//
			this.nodeCtrlVarName.Bounds = new System.Drawing.Rectangle(0, 0, 0, 0);
			this.nodeCtrlVarName.DataPropertyName = "VarName";
			this.nodeCtrlVarName.EditEnabled = false;
			this.nodeCtrlVarName.IncrementalSearchEnabled = true;
			this.nodeCtrlVarName.LeftMargin = 3;
			this.nodeCtrlVarName.ParentColumn = this.tvColVarName;
			this.nodeCtrlVarName.Trimming = System.Drawing.StringTrimming.EllipsisCharacter;
			//
			// nodeCtrlDataType
			//
			this.nodeCtrlDataType.Bounds = new System.Drawing.Rectangle(0, 0, 0, 0);
			this.nodeCtrlDataType.DataPropertyName = "DataType";
			this.nodeCtrlDataType.EditEnabled = false;
			this.nodeCtrlDataType.IncrementalSearchEnabled = true;
			this.nodeCtrlDataType.LeftMargin = 3;
			this.nodeCtrlDataType.ParentColumn = this.tvColDataType;
			this.nodeCtrlDataType.Trimming = System.Drawing.StringTrimming.EllipsisCharacter;
			//
			// nodeCtrlStartVal
			//
			this.nodeCtrlStartVal.Bounds = new System.Drawing.Rectangle(0, 0, 0, 0);
			this.nodeCtrlStartVal.DataPropertyName = "StartValue";
			this.nodeCtrlStartVal.EditOnClick = true;
			this.nodeCtrlStartVal.IncrementalSearchEnabled = true;
			this.nodeCtrlStartVal.LeftMargin = 3;
			this.nodeCtrlStartVal.ParentColumn = this.tvColStartVal;
			this.nodeCtrlStartVal.Trimming = System.Drawing.StringTrimming.EllipsisCharacter;
			this.nodeCtrlStartVal.IsEditEnabledValueNeeded += new System.EventHandler<Aga.Controls.Tree.NodeControls.NodeControlValueEventArgs>(this.nodeCtrlStartVal_IsEditEnabledValueNeeded);
			//
			// calendar
			//
			this.calendar.Location = new System.Drawing.Point(0, 0);
			this.calendar.MaxSelectionCount = 1;
			this.calendar.Name = "calendar";
			this.calendar.TabIndex = 0;
			this.calendar.Visible = false;
			this.calendar.MouseCaptureChanged += new System.EventHandler(this.calender_MouseCaptureChanged);
			this.calendar.DateSelected += new System.Windows.Forms.DateRangeEventHandler(this.calender_DateSelected);
			this.calendar.Leave += new System.EventHandler(this.calender_Leave);
			//
			// EditableBusinessObjectTreeView
			//
			this.Columns.Add(this.tvColVarName);
			this.Columns.Add(this.tvColDataType);
			this.Columns.Add(this.tvColStartVal);
			this.ContextMenuStrip = this.ctxMenuVars;
			this.Controls.Add(this.calendar);
			this.FullRowSelect = true;
			this.GridLineStyle = Aga.Controls.Tree.GridLineStyle.Vertical;
			this.NodeControls.Add(this.nodeCtrlIcon);
			this.NodeControls.Add(this.nodeCtrlVarName);
			this.NodeControls.Add(this.nodeCtrlDataType);
			this.NodeControls.Add(this.nodeCtrlStartVal);
			this.UseColumns = true;
			this.SelectionChanged += new System.EventHandler(this.EditableBusinessObjectTreeView_SelectionChanged);
			this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.EditableBusinessObjectTreeView_MouseDown);
			this.ctxMenuVars.ResumeLayout(false);
			this.ResumeLayout(false);
		}

		private string RandomCity()
		{
			int next = _random.Next(Cities.Count);
			return Cities[next];
		}

		private DateTime RandomDate()
		{
			DateTime start = DateTime.Now;
			int days = _random.Next(7);
			int hours = _random.Next(12);
			return ( start + new TimeSpan(days, hours, 0, 0) );
		}

		private string RandomFirstName()
		{
			int next = _random.Next(FirstNames.Count);
			return FirstNames[next];
		}

		private string RandomFullName()
		{
			string fullName;
			int next = _random.Next(FirstNames.Count);
			fullName = FirstNames[next];
			next = _random.Next(LastNames.Count);
			fullName += " " + LastNames[next];
			return fullName;
		}

		private string RandomLastName()
		{
			int next = _random.Next(LastNames.Count);
			return LastNames[next];
		}

		private void ReadObjectFromXml(XmlNode xmlNode)
		{
			if ( xmlNode == null ) return;
			XmlNamespaceManager xnm = new XmlNamespaceManager(_xmlDoc.NameTable);
			xnm.AddNamespace("n", "http://www.OpenComposite.com/canonical_document");
			SimulationVariable inputObject = rootNode as SimulationVariable;
			foreach ( Node node in inputObject.Nodes ) {
				SimulationVariable simVar = node as SimulationVariable;
				if ( simVar == null ) throw new NullReferenceException("simVar is null. createInputObject()");
				XmlNode child = xmlNode.SelectSingleNode(string.Format("./n:{0}", simVar.VarName), xnm);
				if ( child == null ) continue;
				if ( child.FirstChild == null ) continue;
				if ( child.FirstChild.ChildNodes.Count == 0 ) {
					simVar.StartValue = child.FirstChild.Value;
				} else {
					if ( simVar.DataType.StartsWith("List of") ) {
						for ( int i = 0; i < child.ChildNodes.Count; i++ ) {
							XmlNode listItem = child.ChildNodes[i];
							SimulationVariable simListItem = null;
							if ( simVar.Nodes.Count <= i ) {
								simListItem = AddListElementToNode(simVar);
							} else {
								simListItem = simVar.Nodes[i] as SimulationVariable;
							}
							readNestedObjectFromXml(simListItem, listItem, xnm);
						}
					} else {
						readNestedObjectFromXml(simVar, child, xnm);
					}
				}
			}
		}

		private void SetPropertyValue(PropertyInfo property, Type inputType, object target, object value)
		{
			property.SetValue(target, value, null);
			if ( needsSpecifiedFlag(property.PropertyType) ) {
				PropertyInfo propSpecified = inputType.GetProperty(string.Format("{0}Specified", property.Name));
				if ( propSpecified != null ) {
					propSpecified.SetValue(target, true, null);
				}
			}
		}

		private object calculateSimCycleRowItem(SimulationVariable simVar)
		{
			// decrement because the first column in dtSimCycles is the "Index" column
			Type type = Helpers.GetDotNetTypeOfDataTypeString(simVar.DataType);

			if ( type == typeof(int) ) {
				#region calculate int values
				int v1;
				bool v1ok = int.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(int);
				}
				#endregion
			} else if ( type == typeof(uint) ) {
				#region calculate int values
				uint v1;
				bool v1ok = uint.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(uint);
				}
				#endregion
			} else if ( type == typeof(double) ) {
				#region calculate double values
				double v1;
				bool v1ok = double.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(double);
				}
				#endregion
			} else if ( type == typeof(float) ) {
				#region calculate float values
				float v1;
				bool v1ok = float.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(float);
				}
				#endregion
			} else if ( type == typeof(decimal) ) {
				#region calculate decimal values
				decimal v1;
				bool v1ok = decimal.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(decimal);
				}
				#endregion
			} else if ( type == typeof(long) ) {
				#region calculate long values
				long v1;
				bool v1ok = long.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(ulong);
				}
				#endregion
			} else if ( type == typeof(ulong) ) {
				#region calculate long values
				ulong v1;
				bool v1ok = ulong.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(ulong);
				}
				#endregion
			} else if ( type == typeof(bool) ) {
				#region calculate bool values
				bool v1;
				bool v1ok = bool.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(bool);
				}
				#endregion
			} else if ( type == typeof(string) ) {
				#region calculate string values
				string v1;
				v1 = simVar.StartValue;
				bool v1ok = !string.IsNullOrEmpty(v1);
				if ( v1ok ) {
					return v1;
				} else {
					return string.Empty;
				}
				#endregion
			} else if ( type == typeof(DateTime) ) {
				#region calculate DateTime values
				DateTime v1;
				bool v1ok = DateTime.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(DateTime);
				}
				#endregion
			} else if ( type == typeof(TimeSpan) ) {
				#region calculate TimeSpan values
				TimeSpan v1;
				bool v1ok = TimeSpan.TryParse(simVar.StartValue, out v1);
				if ( v1ok ) {
					return v1;
				} else {
					return default(TimeSpan);
				}
				#endregion
			} else {
				throw new NotSupportedException(string.Format("Type '{0}' not supported by calculation of simulation cycles.", type.ToString()));
			}
		}

		private object createNestedObject(SimulationVariable simVar, Type propertyType)
		{
			if ( propertyType == null ) return null;
			object obj = null;

			string dataNamespace = _wfController.FullClassName.Remove(_wfController.FullClassName.LastIndexOf(_wfController.RepositoryItem.Name)) + "Data.";
			//string baseName = dataNamespace + subPath + "+" + simVar.DataType;
			Type varType = _compiledAssembly.GetType(propertyType.FullName);
			//if ( varType == null ) varType = _currentCompileResults.CompiledAssembly.GetType(baseName + "Type");
			ConstructorInfo ctor = null;
			if ( varType.IsArray ) {
				ctor = varType.GetConstructor(new Type[] { typeof(int) });
				obj = ctor.Invoke(new object[] { simVar.Nodes.Count });
			} else {
				ctor = varType.GetConstructor(Type.EmptyTypes);
				obj = ctor.Invoke(null);
			}

			if ( ( simVar.Field.IsList ) &&
				 ( varType.IsArray || varType.GetMethod("Add") != null ) ) {
				bool isArray = varType.IsArray;
				MethodInfo meth = null;
				if ( isArray ) {
					meth = varType.GetMethod("Set");
					varType = propertyType.GetElementType();
				} else {
					meth = varType.GetMethod("Add");
					varType = propertyType.BaseType.GetGenericArguments()[0];
				}
				int i = 0;
				foreach ( Node element in simVar.Nodes ) {
					object subObj = null;
					ConstructorInfo subCtor = varType.GetConstructor(Type.EmptyTypes);
					subObj = subCtor.Invoke(null);
					foreach ( Node node in element.Nodes ) {
						SimulationVariable nestedVar = node as SimulationVariable;
						if ( nestedVar == null ) throw new NullReferenceException("simVar is null. createInputObject()");

						PropertyInfo prop = varType.GetProperty(nestedVar.VarName);
						if ( nestedVar.Field.BusinessObjectID > 0 ) {
							prop.SetValue(subObj, createNestedObject(nestedVar, prop.PropertyType), null);
						} else if ( nestedVar.Field.NounID > 0 ) {
							SetPropertyValue(prop, varType, subObj, calculateSimCycleRowItem(nestedVar));
						}
					}
					if ( isArray ) {
						meth.Invoke(obj, new object[] { i, subObj });
						i++;
					} else {
						meth.Invoke(obj, new object[] { subObj });
					}
				}
			} else {
				foreach ( Node node in simVar.Nodes ) {
					SimulationVariable nestedVar = node as SimulationVariable;
					if ( nestedVar == null ) throw new NullReferenceException("simVar is null. createInputObject()");

					PropertyInfo prop = varType.GetProperty(nestedVar.VarName);
					if ( nestedVar.Field.BusinessObjectID > 0 ) {
						prop.SetValue(obj, createNestedObject(nestedVar, prop.PropertyType), null);
					} else if ( nestedVar.Field.NounID > 0 ) {
						SetPropertyValue(prop, varType, obj, calculateSimCycleRowItem(nestedVar));
						//prop.SetValue(obj, calculateSimCycleRowItem(nestedVar), null);
					}
				}
			}
			return obj;
		}

		private SimulationVariable createNodeRow(BusinessObjectField field)
		{
			SimulationVariable sv = new SimulationVariable(field);
			if ( field.BusinessObjectID > 0 ) {
				if ( field.IsList ) {
					sv.Image = ImageBusinessObjectList;
					AddListElementToNode(sv);
				} else {
					sv.Image = ImageBusinessObject;
					foreach ( BusinessObjectField subField in field.BusinessObject.BusinessObjectFields ) {
						sv.Nodes.Add(createNodeRow(subField));
					}
				}
			} else if ( field.NounID > 0 ) {
				sv.Image = ImageNoun;
			}

			return sv;
		}

		private void generateTree()
		{
			TreeModel model = new TreeModel();
			if ( _bobjects != null /*&& _bobjects.Count > 0*/ ) {
				if ( _xmlDoc != null && _xmlBobject != null ) {
					#region Input Document
					if ( inputFolder == null ) {
						inputFolder = new SimulationVariable("Input Document");
					} else {
						inputFolder.Nodes.Clear();
					}
					inputFolder.Image = ImageFolder;
					SimulationVariable simVar = new SimulationVariable(_xmlBobject.Name, _xmlBobject);
					foreach ( BusinessObjectField field in _xmlBobject.BusinessObjectFields ) {
						simVar.Nodes.Add(createNodeRow(field));
					}
					simVar.Image = ImageBusinessObject;
					inputFolder.Nodes.Add(simVar);

					model.Root.Nodes.Add(inputFolder);
					#endregion
				}
				if ( _outputBusinessObject != null ) {
					#region Output Document ( Published)
					if ( outputFolder == null ) {
						outputFolder = new SimulationVariable("Published Document");
					} else {
						outputFolder.Nodes.Clear();
					}
					outputFolder.Image = ImageFolder;
					SimulationVariable simVar = new SimulationVariable(_outputBusinessObject);
					foreach ( BusinessObjectField field in _outputBusinessObject.BusinessObject.BusinessObjectFields ) {
						simVar.Nodes.Add(createNodeRow(field));
					}
					simVar.Image = ImageBusinessObject;
					outputFolder.Nodes.Add(simVar);

					model.Root.Nodes.Add(outputFolder);
					#endregion
				}
				if ( subscribedFolder == null ) {
					subscribedFolder = new SimulationVariable("Subscribed Documents");
				} else {
					subscribedFolder.Nodes.Clear();
				}
				subscribedFolder.Image = ImageFolder;
				foreach ( NamedBusinessObject item in _bobjects ) {
					if ( item == null || item.BusinessObject == null ) continue;
					SimulationVariable simVar = new SimulationVariable(item);
					rootNode = simVar;
					simVar.Image = ImageBusinessObject;

					foreach ( BusinessObjectField field in item.BusinessObject.BusinessObjectFields ) {
						simVar.Nodes.Add(createNodeRow(field));
					}

					if ( _additionalBObjects != null && _additionalBObjects.Count > 0 ) {
						subscribedFolder.Nodes.Add(simVar);
					} else {
						model.Root.Nodes.Add(simVar);
					}
				}
				if ( _additionalBObjects != null && _additionalBObjects.Count > 0 ) {
					model.Root.Nodes.Add(subscribedFolder);
					if ( othersFolder == null ) {
						othersFolder = new SimulationVariable("Other Documents");
					} else {
						othersFolder.Nodes.Clear();
					}
					othersFolder.Image = ImageFolder;
					foreach ( NamedBusinessObject item in _additionalBObjects ) {
						SimulationVariable simVar = new SimulationVariable(item);
						rootNode = simVar;
						simVar.Image = ImageBusinessObject;

						foreach ( BusinessObjectField field in item.BusinessObject.BusinessObjectFields ) {
							simVar.Nodes.Add(createNodeRow(field));
						}
						othersFolder.Nodes.Add(simVar);
					}
					model.Root.Nodes.Add(othersFolder);
				}
			} else {
				rootNode = new SimulationVariable(_nBobject == null ? null : _nBobject.Name, _bobject);
				rootNode.Image = ImageBusinessObject;
				model.Root.Nodes.Add(rootNode);
				foreach ( BusinessObjectField field in _bobject.BusinessObjectFields ) {
					rootNode.Nodes.Add(createNodeRow(field));
				}
			}
			this.Model = model;
			if ( _bobjects != null && _bobjects.Count > 0 ) {
				TreeNodeAdv ifn = this.FindNodeByTag(inputFolder);
				if ( ifn != null ) ifn.ExpandAll();

				TreeNodeAdv ofn = this.FindNodeByTag(outputFolder);
				if ( ofn != null ) ofn.ExpandAll();
				if ( ifn == null && ofn == null ) {
					TreeNodeAdv sfn = this.FindNodeByTag(subscribedFolder);
					if ( sfn != null ) sfn.ExpandAll();
				}
			} else {
				this.Root.ExpandAll();
			}
		}

		private void init()
		{
		}

		private void load()
		{
			if ( _bobject == null && ( _bobjects == null /*|| _bobjects.Count == 0*/ ) ) return;
			if ( _bobject == null && ( _bobjects != null /*&& _bobjects.Count > 0*/ ) ) _readOnly = true;
			if ( _wfController == null ) return;
			generateTree();
		}

		private bool needsSpecifiedFlag(Type t)
		{
			return needsSpecifiedFlag(t.Name);
		}

		private bool needsSpecifiedFlag(string type)
		{
			if ( type == "int" || type == "Int16" || type == "Int32" || type == "Int64" ) return true;
			if ( type == "float" || type == "Single" ) return true;
			if ( type == "double" ) return true;
			if ( type == "decimal" || type == "Decimal" ) return true;
			if ( type == "DateTime" ) return true;
			if ( type == "TimeSpan" ) return true;

			return false;
		}

		private void readNestedObject(SimulationVariable simVar, object rootObj,
			object subObj, PropertyInfo property)
		{
			string dataNamespace = _wfController.FullClassName.Remove(_wfController.FullClassName.LastIndexOf(_wfController.RepositoryItem.Name)) + "Data.";
			Type varType = _compiledAssembly.GetType(property.PropertyType.FullName);

			if ( simVar.Field.IsList &&
				 ( varType.IsArray || varType.GetMethod("Add") != null ) ) {
				int count = 0;
				bool isArray = varType.IsArray;
				if ( isArray ) {
					count = (int)property.PropertyType.GetProperty("Length").GetValue(subObj, null);
					varType = property.PropertyType.GetElementType();
				} else {
					count = (int)property.PropertyType.GetProperty("Count").GetValue(subObj, null);
					varType = property.PropertyType.BaseType.GetGenericArguments()[0];
				}
				if ( count == 0 ) {
					simVar.Nodes.Clear();
					return;
				}
				for ( int i = 0; i < count; i++ ) {
					object startObject = null;
					if ( isArray ) {
						MethodInfo meth = property.PropertyType.GetMethod("Get");
						startObject = meth.Invoke(subObj, new object[] { i });
					} else {
						PropertyInfo listProperty = property.PropertyType.GetProperty("Item");
						startObject = listProperty.GetValue(subObj, new object[] { i });
					}
					if ( simVar.Nodes.Count <= i ) AddListElementToNode(simVar);
					foreach ( Node node in simVar.Nodes[i].Nodes ) {
						SimulationVariable nestedVar = node as SimulationVariable;
						if ( nestedVar == null ) throw new NullReferenceException("simVar is null. createInputObject()");

						PropertyInfo prop = varType.GetProperty(nestedVar.VarName);
						if ( nestedVar.Field.BusinessObjectID > 0 ) {
							object field = prop.GetValue(startObject, null);
							if ( field == null ) {
								nestedVar.StartValue = null;
								break;
							} else {
								SimulationVariable listVar = new SimulationVariable(string.Format("{0} {1}", nestedVar.Field.DataType, i + 1), nestedVar.Field);
								listVar.Image = ImageBusinessObject;
								readNestedObject(listVar, rootObj, field, prop);
								nestedVar.Nodes.Add(listVar);
							}
						} else if ( nestedVar.Field.NounID > 0 ) {
							nestedVar.StartValue = prop.GetValue(startObject, null).ToString();
						}
					}
				}
				//object subObj = null;
				//ConstructorInfo subCtor = varType.GetConstructor(Type.EmptyTypes);
				//subObj = subCtor.Invoke(null);

			} else {
				readNodes(simVar.Nodes, rootObj, subObj, varType);
				#region Old Code
				//foreach ( Node node in simVar.Nodes ) {
				//    SimulationVariable nestedVar = node as SimulationVariable;
				//    if ( nestedVar == null ) throw new NullReferenceException("simVar is null. createInputObject()");

				//    PropertyInfo prop = varType.GetProperty(nestedVar.VarName);
				//    if ( nestedVar.Field.BusinessObjectID > 0 ) {
				//        //prop.SetValue(obj, createNestedObject(nestedVar, prop), null);
				//    } else if ( nestedVar.Field.NounID > 0 ) {
				//        //prop.SetValue(obj, calculateSimCycleRowItem(nestedVar), null);
				//    }
				//}
				#endregion
			}
		}

		private void readNestedObjectFromXml(SimulationVariable simVar, XmlNode xmlNode,
			XmlNamespaceManager manager)
		{
			foreach ( Node node in simVar.Nodes ) {
				SimulationVariable nodeVar = node as SimulationVariable;
				if ( nodeVar == null ) throw new NullReferenceException("simVar is null. at readNestedObjectFromXml()");
				XmlNode child = xmlNode.SelectSingleNode(string.Format("./n:{0}", nodeVar.Field.Name), manager);
				// nested array handling
				if ( child == null && nodeVar.Field.IsList ) child = xmlNode;
				if ( child == null ) continue;
				if ( nodeVar.DataType.StartsWith("List of") ) {
					for ( int i = 0; i < child.ChildNodes.Count; i++ ) {
						XmlNode listItem = child.ChildNodes[i];
						SimulationVariable simListItem = null;
						if ( nodeVar.Nodes.Count <= i ) {
							simListItem = AddListElementToNode(nodeVar);
						} else {
							simListItem = nodeVar.Nodes[i] as SimulationVariable;
						}
						readNestedObjectFromXml(simListItem, listItem, manager);
					}
				}
				if ( child.FirstChild == null ) continue;
				if ( child.FirstChild == child.LastChild &&
					child.FirstChild.ChildNodes.Count == 0 ) {
					nodeVar.StartValue = child.FirstChild.Value;
				} else {
					readNestedObjectFromXml(nodeVar, child, manager);
				}

			}
		}

		private bool readNode(Node node, object rootObj, object objToRead, Type varType)
		{
			SimulationVariable simVar = node as SimulationVariable;
			if ( simVar == null ) throw new NullReferenceException("simVar is null. createInputObject()");

			PropertyInfo prop = varType.GetProperty(simVar.VarName);
			if ( simVar.Field.BusinessObjectID > 0 ) {
				object obj = prop.GetValue(rootObj, null);
				if ( obj == null ) {
					simVar.StartValue = null;
					return false;
				} else {
					simVar.StartValue = "...";
					readNestedObject(simVar, rootObj, obj, prop);
				}
			} else if ( simVar.Field.NounID > 0 ) {
				object obj = prop.GetValue(objToRead, null);
				if ( obj == null ) return true;
				simVar.StartValue = obj.ToString();
			}
			return true;
		}

		private void readNodes(Collection<Node> nodes, object rootObj, object objToRead, Type varType)
		{
			foreach ( Node node in nodes ) {
				if ( !readNode(node, rootObj, objToRead, varType) ) break;
			}
		}

		private SimulationVariable setSelectedNodeValue(SimulationVariable node, string value)
		{
			node.StartValue = value;
			this.FullUpdate();
			return node;
		}

		#endregion Methods

		#endregion Private Members
	}

	public class SimulationVariable : Node
	{
		#region Initialization

		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationVariable"/> class. This constructor should only be used in read only mode
		/// </summary>
		/// <param name="text">The display text.</param>
		public SimulationVariable(string text)
		{
			_varName = text;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationVariable"/> class with a specified display text.
		/// </summary>
		/// <param name="text">The display text.</param>
		/// <param name="field">The <see cref="BusinessObjectField"/> of this <see cref="SimulationVariable"/>.</param>
		public SimulationVariable(string text, BusinessObjectField field)
		{
			_varName = text;
			_dataType = field.DataType;
			_field = field;
			setTag();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationVariable"/> class.
		/// </summary>
		/// <param name="field">The <see cref="BusinessObjectField"/> of this <see cref="SimulationVariable"/>.</param>
		public SimulationVariable(BusinessObjectField field)
		{
			_varName = field.Name;
			if ( field.IsList ) {
				_dataType = string.Format("List of {0}", field.DataType);
			} else {
				_dataType = field.DataType;
			}
			_field = field;
			setTag();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationVariable"/> class.
		/// </summary>
		/// <param name="rootObject">The root <see cref="BusinessObject"/> of this <see cref="SimulationVariable"/>.</param>
		//public SimulationVariable(BusinessObject rootObject)
		//{
		//	_varName = rootObject.Name;
		//	_dataType = rootObject.Name;
		//	_rootObjects = new NamedBusinessObject(rootObject.Name, rootObject, null);
		//	this.Tag = rootObject;
		//}
		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationVariable"/> class.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="rootObject">The root object.</param>
		public SimulationVariable(string text, BusinessObject rootObject)
		{
			_varName = text;
			_dataType = rootObject.Name;
			_rootObjects = new NamedBusinessObject(text, rootObject);
			this.Tag = rootObject;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationVariable"/> class.
		/// </summary>
		/// <param name="rootObject">The root object.</param>
		public SimulationVariable(NamedBusinessObject rootObject)
		{
			_varName = rootObject.Name;
			_dataType = rootObject.BusinessObject.Name;
			_rootObjects = rootObject;
			this.Tag = rootObject;
		}

		#endregion Initialization

		#region Public Members

		#region Properties

		public string DataType
		{
			get { return _dataType; }
			set { _dataType = value; }
		}

		public string Distribution
		{
			get { return _distribution; }
			set { _distribution = value; }
		}

		public BusinessObjectField Field
		{
			get { return _field; }
			set { _field = value; }
		}

		public Bitmap Icon
		{
			get
			{
				if ( _field == null )
					return Resources.bobject;

				if ( _field.BusinessObjectID > 0 ) {
					if ( _field.MinOccurs == -1 || _field.MinOccurs > 0 ) {
						return Resources.list_of_bobjects;
					}
				} else if ( _field.NounID > 0 ) {
					return Resources.png_field;
				}
				return Resources.bobject;
			}
		}

		public string StartValue
		{
			get { return _startValue; }
			set
			{
				if ( value != null && !string.IsNullOrEmpty(_dataType) ) {
					if ( checkValue(ref value) ) {
						_startValue = value;
					} else {
						return;
					}
				} else {
					_startValue = value;
				}
			}
		}

		public int Steps
		{
			get { return _steps; }
			set { _steps = value; }
		}

		public string VarName
		{
			get { return _varName; }
			set { _varName = value; }
		}

		#endregion Properties

		#region Methods

		/// <summary>
		/// Returns a <see cref="String"/> that represents the current <see cref="Object"/>.
		/// </summary>
		/// <returns>
		/// A <see cref="String"/> that represents the current <see cref="Object"/>.
		/// </returns>
		public override string ToString()
		{
			StringBuilder sb = new StringBuilder();
			sb.AppendFormat("{0} ", _dataType);
			sb.Append(_varName);
			if ( !string.IsNullOrEmpty(_startValue) ) {
				sb.AppendFormat(" ({0}", _startValue);
				if ( !string.IsNullOrEmpty(_endValue) ) {
					sb.AppendFormat(" - {0}", _endValue);
				}
				sb.Append(")");
			}
			return sb.ToString();
		}

		#endregion Methods

		#endregion Public Members

		#region Private Members

		#region Fields

		private string _dataType = null;
		private string _distribution = "None";
		private string _endValue = null;
		private BusinessObjectField _field = null;
		private NamedBusinessObject _rootObjects = null;
		private string _startValue = null;
		private int _steps = 0;
		private string _varName = null;

		#endregion Fields

		#region Properties

		[Obsolete]
		private string EndValue
		{
			get { return _endValue; }
			set { _endValue = value; }
		}

		#endregion Properties

		#region Methods

		/// <summary>
		/// Checks if the value confirms to the data type. Also corrects possible errors in floating point numbers.
		/// </summary>
		/// <param name="value">The value to check.</param>
		/// <returns></returns>
		private bool checkValue(ref string value)
		{
			bool valueOk = false;
			NumberFormatInfo numberFormat = NumberFormatInfo.InvariantInfo;
			if ( _dataType == "int" ) {
				int result = 0;
				valueOk = int.TryParse(value, NumberStyles.Integer, numberFormat, out result);
			} else if ( _dataType == "float" ) {
				if ( CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == "," ) {
					value = value.Replace('.', ',');
				} else if ( CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == "." ) {
					value = value.Replace(',', '.');
				}
				float result = 0.0F;
				valueOk = float.TryParse(value, /*numberStyle, numberFormat,*/ out result);
			} else if ( _dataType == "double" ) {
				if ( CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == "," ) {
					value = value.Replace('.', ',');
				} else if ( CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == "." ) {
					value = value.Replace(',', '.');
				}
				double result = 0.0;
				valueOk = double.TryParse(value, /*numberStyle, numberFormat,*/ out result);
			} else if ( _dataType == "decimal" ) {
				if ( CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == "," ) {
					value = value.Replace('.', ',');
				} else if ( CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == "." ) {
					value = value.Replace(',', '.');
				}
				decimal result = 0.0M;
				valueOk = decimal.TryParse(value, /*numberStyle, numberFormat,*/ out result);
			} else if ( _dataType == "dateTime" ) {
				DateTime result = DateTime.MinValue;
				valueOk = DateTime.TryParse(value, out result);
			} else if ( _dataType == "string" ) {
				valueOk = true;
			} else if ( _dataType == "long" ) {
				long result = 0;
				valueOk = long.TryParse(value, NumberStyles.Integer, numberFormat, out result);
			} else if ( _dataType == "unsignedLong" ) {
				ulong result = 0;
				valueOk = ulong.TryParse(value, NumberStyles.Integer, numberFormat, out result);
			} else if ( _dataType == "bool" ) {
				bool result = false;
				valueOk = bool.TryParse(value, out result);
			} else if ( _dataType == "TimeSpan" ) {
				TimeSpan result = TimeSpan.Zero;
				valueOk = TimeSpan.TryParse(value, out result);
			} else {
				throw new NotImplementedException("This data type is not supported yet!");
			}

			if ( !valueOk ) {
				MessageBox.Show("Value is not in correct format!", "Format error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
			}
			return valueOk;
		}

		private void setTag()
		{
			if ( _field.BusinessObjectID > 0 ) this.Tag = _field.BusinessObject;
			else this.Tag = _field.Noun;
		}

		#endregion Methods

		#endregion Private Members
	}
}
